package org.kev.transit;

import java.util.*;

import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;

import org.kev.transit.data.Stop;
import org.kev.transit.util.TransitConst;
import org.kev.transit.util.TransitUtil;
import org.kev.transit.worker.DataWorker;
import org.kev.transit.worker.LocationWorker;

/**
 * Stop/ Station screen.   
 * The data displayed is based on a Web service(JSON) call that is then cached in
 * the local DB.  Someday it will also expire cached data in the DB.  All DB updates 
 * occur in a background thread.
 * @author kevin
 *
 */
public class StopActivity extends DataActivity {
	public static final int MAP_ID = FIRST_MENU + 1;
	public static final int FIND_STOP_ID = FIRST_MENU + 2;
	public static final String TAG = "Transit";
	private static final DataWorker mWorker = new DataWorker();
	private static final LocationWorker mLocWorker = new LocationWorker();
	// private EditText mEditor;
	private ListView mListView = null;
	private int closestIdx=0;
	private ArrayAdapter<Stop> arrayAdaptor = null;
	final Handler mHandler = new Handler();
	protected int progress = 0;
	//private Cursor mCursor;

	public StopActivity() {

	}

	/**
	 * Called when fist started
	 * 
	 * @param icicle
	 */
	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		try {

			// Inflate our UI from its XML layout description.
			 requestWindowFeature(Window.FEATURE_PROGRESS);
			Log.d(TAG, "INFLAGE XML!!!");
			setContentView(R.layout.stop);
	        setProgressBarVisibility(true);
	        setProgressBarIndeterminate(true);
			// final String type = intent.resolveType(this);
			// Find the text view inside the layout

			mListView = (ListView) findViewById(R.id.stopList);

			// setRouteTypeData();
			mListView.setOnItemSelectedListener(mStopListener);
			mListView.setOnItemClickListener(mItemListener);
	    	// Hook up button presses to the appropriate event handler.
			// ((Button)
			// findViewById(R.id.back)).setOnClickListener(mBackListener);
			// ((Button)
			// findViewById(R.id.next)).setOnClickListener(mNextListener);
			((Button) findViewById(R.id.map)).setOnClickListener(mMapListener);

		} catch (Exception e) {
			Log.e(TransitConst.TAG, "UKNOWN Error in " + this, e);
			AlertDialog.show(this, "StackTrace",R.drawable.icon,e.getMessage(), "Ok", false);
		}
	}

	/**
	 * Called when the activity is about to start interacting with the user.
	 */
	@Override
	protected void onResume() {
		super.onResume();
		mWorker.init(this, mHandler, mUpdateResults);
		Thread t = new Thread(mWorker);
		t.setDaemon(true);
		t.start();
		setProgressBarVisibility(true);
		 Log.d(TAG,".onResume restore Prefs !");
			SharedPreferences settings = getSharedPreferences(TransitConst.PREFS_NAME,0);
			TransitConf.currentStop = settings.getString(TransitConst.STOP_PREF, "none");
			Log.d(TAG,"Current stop="+TransitConf.currentStop);

	}

	/**
	 * 
	 * I am being paused save all prefs
	 */
	@Override
	protected void onPause() {
		super.onPause();

		Log.d(TransitConst.TAG, "onPAUSE Save Prefs!");
		Log.d(TransitConst.TAG, TransitConf.toXML());
		TransitUtil.savePref(this,TransitConst.STOP_PREF,TransitConf.currentStop);
	}

	@Override
	protected void onFreeze(Bundle outState) {
		super.onFreeze(outState);
		//TransitUtil.savePref(this,TransitConst.STOP_PREF,TransitConf.currentStop);
		//outState.putBundle(TAG, mListView.saveState());
	}

	/**
	 * 
	 * 
	 * /** Called when your activity's options menu needs to be created.
	 * 
	 * @param menu
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);

		// We are going to create two menus. Note that we assign them
		// unique integer IDs, labels from our string resources, and
		// given them shortcuts.
		menu.add(0, MAP_ID, R.string.map).setShortcut('1','m');
		menu.add(0, FIND_STOP_ID, R.string.find_stop).setShortcut(
				'2', 'f');
		return true;
	}

	/**
	 * Called right before your activity's option menu is displayed.
	 * 
	 * @param menu
	 */
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		super.onPrepareOptionsMenu(menu);

		// Before showing the menu, we need to decide whether the clear
		// item is enabled depending on whether there is text to clear.
		// menu.setItemShown(CLEAR_ID, mEditor.getText().length() > 0);

		return true;
	}

	/**
	 * Called when a menu item is selected.
	 * 
	 * @param item
	 * 
	 */
	@Override
	public boolean onOptionsItemSelected(Menu.Item item) {
		switch (item.getId()) {
		case MAP_ID:
			mapScreen();
			return true;
		case FIND_STOP_ID:
			
			mLocWorker.init(this, mHandler, mLocationResults);
			Thread t = new Thread(mLocWorker);
			t.start();
			// findStop();
			return true;
		}

		return super.onOptionsItemSelected(item);
	}

	/**
	 * finds the stop (station) that is the smallest distance away from the
	 * current location. I had to use doubles in order not loose significant
	 * digits need to think of a better way to calculate this using integers
	 * 
	 */
	public void findStop() {
		LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		Location currentLoc = locManager.getCurrentLocation("gps");
		if (currentLoc==null){
			currentLoc = locManager.getCurrentLocation("cell");
			if(currentLoc==null){
				Log.e(TAG,"Location not found using GPS or Cell ID");
				return ;
			}
		}
		double dlat =  currentLoc.getLatitude();
		double dlon =  currentLoc.getLongitude();

		// Log.d(TAG,"current projected clat"+clat+" clon="+clon);

		int listSize = arrayAdaptor.getCount();

		double bestDist = Float.MAX_VALUE;
		int bestIndex = 0;
		/*
		 *  Something like the following would provide an accurate distance calculation 
		 * =6378.135 *ACOS(COS(RADIANS(90-(Lat1*24)))*COS(RADIANS(90-(Lat2*24)))+
		 * SIN(RADIANS(90-(Lat1*24)))*SIN(RADIANS(90-(Lat2*24)))*
		 * COS(RADIANS(24*(Long1-Long2))))
		 * The above will calculate the great circle ie distance a bird would fly in north west hemisphere.
		 * I am not using the above because I want to avoid all of the floating point math.  The above would need
		 * to be run for each stop(station). 
		 */
		// spin though list view in order to calculate what station in the list
		// is the smallest distance from our current gps location
		for (int i = 0; i < listSize; i++) {
			Stop data = arrayAdaptor.getItem(i);
			Log.d(TAG, "\nstop dlat" + data.lat + " dlon=" + data.lon);
			double stationLat = Double.valueOf(data.lat);
			double stationLon = Double.valueOf(data.lon);
			Log.d(TAG, "\nstop lat" + stationLat + " lon=" + stationLon);
			// TODO modify this to work around the when longitudes or latitudes have different signs
			//currently this will only work in when the signs are the same
			double latDiff = Math.abs(dlat) - Math.abs(stationLat);
			latDiff = Math.abs(latDiff); // drop any sign
			double lonDiff = Math.abs(Math.abs(dlon) - Math.abs(stationLon));
 
			Log.d(TAG, "latDiff=" + latDiff + " lonDiff=" + lonDiff);
			// I am going to pretend the difference in lat and long is the distance of 2 sides of a right
			// triangle and that the world is flat!  Then use the Pythagorean theorem to solve the distance between
			// the points.  Note if lat and lon are left as an integer I can often get a result that is NaN   
			double dist = Math.sqrt(((latDiff * latDiff) + (lonDiff * lonDiff)));
			Log.d(TAG, "dist=" + dist);
			if (dist < bestDist) {
				bestDist = dist;
				Log.d(TAG, "=>name =" + data.title);
				Log.d(TAG, "=>bestDiff =" + bestDist);
				bestIndex = i;
				// bstop=data;
			}
		}
		Log.d(TAG, "best idx=" + bestIndex + "try to select it now");
		//mListView.setSelection(bestIndex);
		closestIdx=bestIndex;
	//	stopSelected();
		// setCurrentStop(bstop.name);
	}

	/**
	 * Jump to next Screen (TimeTableActivity)
	 */
	public void nextScreen() {

		startActivity(TransitConst.TIME_TABLE_INTENT );
	}

	public void mapScreen() {
		startActivity(TransitConst.TRANSIT_MAP_INTENT );
	}

	/**
	 * set Data on this List view
	 */
	public void setData() {
		Cursor cursor=null;
		try {

			String rType = TransitConf.currentRouteTypeId;
			String route = TransitConf.currentRouteId;
			String dir = TransitConf.currentDirectionId;
			if (rType == null || route == null || dir == null) { // if any
																	// are null
																	// do not
																	// set any
																	// data
				Log.e(TAG,"Found error "+rType+route+dir);
				return;
			}
			ArrayList <Stop> list = Stop.getData(this, rType, route, dir);
			arrayAdaptor = new ArrayAdapter<Stop>(this,android.R.layout.simple_list_item_1, list);

		} catch (Exception e) {
			Log.e(TAG, "setDirction()", e);
		} finally {
			if (cursor != null)
				cursor.close();
		}
	}

	/**
	 * save selected item in a TransitConf object
	 */
	private void stopSelected() {

		Log.d(TransitConst.TAG, "Stop selected");

		if (mListView.getSelectedItem() != null) {
			Stop data = (Stop) mListView.getSelectedItem();
			Log.d(TAG,"stopData="+data.toXml() );
			// TransitConf.currentStop=temp;
			// String id = stopIds.get(temp);
			// Log.d(TAG,"id="+id+" name="+temp);
			// TransitConf.currentStopId=id;
			// TransitConf.currentLat=Float.valueOf(lats.get(id));
			// Log.d(TAG,"current lat="+TransitConf.currentLat);
			// TransitConf.currentLon =Float.valueOf(lons.get(id));
			TransitConf.currentStopId = data.id;
			TransitConf.currentStop = data.title;
			if(data.lat!=null)
				TransitConf.currentLat = Double.valueOf(data.lat);
			if(data.lon!=null)
				TransitConf.currentLon = Double.valueOf(data.lon);
			Log.d(TAG, "station GPS lat=" + TransitConf.currentLat
					+ TransitConf.currentLon);
			// Log.d(TAG,"id="+id+" name="+temp);

		}

	}

	/**
	 * set the currently select direction item based on pref if it exist
	 * 
	 * @param stopList
	 */
	private void setCurrentStop(ListView stopList) {
		SharedPreferences settings = getSharedPreferences(
				TransitConst.PREFS_NAME, 0);
		String current = settings.getString(TransitConst.STOP_PREF, "none");

	//	Log.d(TAG, "current stop pref=" + current);
		ListAdapter adapter = stopList.getAdapter();
		int count = stopList.getCount();
		Log.d(TAG,"count="+count);
		for (int i = 0; i < count; i++) {
		//	Log.d(TAG,"stopList="+stopList+" adapt="+adapter+" item="+ adapter.getItem(i));
			Object o = adapter.getItem(i);
			String s= null;
			if(o!=null)
				s = adapter.getItem(i).toString();
			Log.d(TransitConst.TAG, "current pref=" + current);
			if ( s != null && s.equals(current)) {
				Log.d(TransitConst.TAG, "found slection=" + s);
				stopList.setSelection(i);
				return;
			}
		}

	}

	private void updateUi() {
		mListView.setAdapter(arrayAdaptor);
		//mListView.restoreState(arg0)
		setCurrentStop(mListView);
	}

	// ****************INNER CLASSES***********************************
	// Create runnable for posting

	/**
	 * Create runnable for posting UI updates
	 */
	Runnable mUpdateResults = new Runnable() {

		public void run() {
			Log.d(TAG, "set mUpdateResults.run()=" + arrayAdaptor);
			updateUi();

			 setProgressBarVisibility(false); 
		}
	};
	/**
	 * Create runnable for posting UI updates
	 */
	Runnable mLocationResults = new Runnable() {

		public void run() {
			Log.d(TAG, "set mLocationResults.run()=" + arrayAdaptor);
			//mListView.setAdapter(arrayAdaptor);
			//setCurrentStop(mListView);
			Log.d(TAG,"set selection="+closestIdx);
			mListView.setSelected(true);
			mListView.setSelection(closestIdx);
			//mListView.requestFocus();
			
			//mListView.bringToFront();
			 setProgressBarVisibility(false); 
		}
	};
	/**
	 * A call-back for click on a selected item
	 */
	OnItemClickListener mItemListener = new OnItemClickListener() {

		public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
			nextScreen();

		}
	};
	/**
	 * A call-back for when the user presses the Next button.
	 */
	OnClickListener mNextListener = new OnClickListener() {
		public void onClick(View v) {
			nextScreen();
		}
	};
	/**
	 * A call-back for when the user presses the back button.
	 */
	OnClickListener mBackListener = new OnClickListener() {
		public void onClick(View v) {
			finish();
		}
	};
	/**
	 * A call-back for when the user presses the back button.
	 */
	OnClickListener mMapListener = new OnClickListener() {
		public void onClick(View v) {
			mapScreen();
		}
	};
	/**
	 * A call-back for when select a stop.
	 */
	OnItemSelectedListener mStopListener = new OnItemSelectedListener() {
		public void onItemSelected(AdapterView parent, View v, int position,
				long id) {
			Log.d(TAG,"selected="+position);
			stopSelected();			
		}

		public void onNothingSelected(AdapterView parent) {
			Log.d(TAG,"nothing selected"+parent);
		}
	};

	private class StopData {
		protected String id = null;
		protected String name = null;
		protected String lat = null;
		protected String lon = null;

		protected StopData(String id, String name, String lat, String lon) {
			this.id = id;
			this.name = name;
			this.lat = lat;
			this.lon = lon;
		}

		public String toString() {
			return name;
		}

	}

}